describe('Object', function() {
	"use strict";

	describe("Object.keys", function() {
				var obj = {
					"str" : "boz",
					"obj" : {},
					"arr" : [],
					"bool" : true,
					"num" : 42,
					"null" : null,
					"undefined" : undefined
				};

				var loopedValues = [];
				for (var k in obj) {
					loopedValues.push(k);
				}

				var keys = Object.keys(obj);
				it('should have correct length', function() {
							expect(keys.length).toBe(7);
						});

				it('should return an Array', function() {
							expect(Array.isArray(keys)).toBe(true);
						});

				it('should return names which are own properties', function() {
							keys.forEach(function(name) {
										expect(obj.hasOwnProperty(name))
												.toBe(true);
									});
						});

				it('should return names which are enumerable', function() {
							keys.forEach(function(name) {
										expect(loopedValues.indexOf(name))
												.toNotBe(-1);
									})
						});

				it('should throw error for non object', function() {
							var e = {};
							expect(function() {
										try {
											Object.keys(42)
										} catch (err) {
											throw e;
										}
									}).toThrow(e);
						});
			});

	describe("Object.isExtensible", function() {
		var obj = {};

		it('should return true if object is extensible', function() {
					expect(Object.isExtensible(obj)).toBe(true);
				});

		it('should return false if object is not extensible', function() {
					expect(Object.isExtensible(Object.preventExtensions(obj)))
							.toBe(false);
				});

		it('should return false if object is seal', function() {
					expect(Object.isExtensible(Object.seal(obj))).toBe(false);
				});

		it('should return false if object is freeze', function() {
					expect(Object.isExtensible(Object.freeze(obj))).toBe(false);
				});

		it('should throw error for non object', function() {
					var e1 = {};
					expect(function() {
								try {
									Object.isExtensible(42)
								} catch (err) {
									throw e1;
								}
							}).toThrow(e1);
				});
	});

	describe("Object.defineProperty", function() {
				var obj;

				beforeEach(function() {
							obj = {};

							Object.defineProperty(obj, 'name', {
										value : 'Testing',
										configurable : true,
										enumerable : true,
										writable : true
									});
						});

				it('should return the initial value', function() {
							expect(obj.hasOwnProperty('name')).toBeTruthy();
							expect(obj.name).toBe('Testing');
						});

				it('should be setable', function() {
							obj.name = 'Other';
							expect(obj.name).toBe('Other');
						});

				it('should return the parent initial value', function() {
							var child = Object.create(obj, {});

							expect(child.name).toBe('Testing');
							expect(child.hasOwnProperty('name')).toBeFalsy();
						});

				it('should not override the parent value', function() {
							var child = Object.create(obj, {});

							Object.defineProperty(child, 'name', {
										value : 'Other'
									});

							expect(obj.name).toBe('Testing');
							expect(child.name).toBe('Other');
						});

				it('should throw error for non object', function() {
							expect(function() {
										Object.defineProperty(42, 'name', {});
									}).toThrow();
						});
			});

	describe("Object.getOwnPropertyDescriptor", function() {
		it(
				'should return undefined because the object does not own the property',
				function() {
					var descr = Object.getOwnPropertyDescriptor({}, 'name');

					expect(descr).toBeUndefined()
				});

		it('should return a data descriptor', function() {
					var descr = Object.getOwnPropertyDescriptor({
								name : 'Testing'
							}, 'name');

					expect(descr).not.toBeUndefined();
					expect(descr.value).toBe('Testing');
					expect(descr.writable).toBe(true);
					expect(descr.enumerable).toBe(true);
					expect(descr.configurable).toBe(true);
				});

		it(
				'should return undefined because the object does not own the property',
				function() {
					var descr = Object.getOwnPropertyDescriptor(Object.create({
										name : 'Testing'
									}, {}), 'name');

					expect(descr).toBeUndefined()
				});

		it('should return a data descriptor', function() {
					var obj = Object.create({}, {
								name : {
									value : 'Testing',
									configurable : true,
									enumerable : true,
									writable : true
								}
							});

					var descr = Object.getOwnPropertyDescriptor(obj, 'name');

					expect(descr).not.toBeUndefined();
					expect(descr.value).toBe('Testing');
					expect(descr.writable).toBe(true);
					expect(descr.enumerable).toBe(true);
					expect(descr.configurable).toBe(true);
				});

		it('should throw error for non object', function() {
					expect(function() {
								Object.getOwnPropertyDescriptor(42, 'name');
							}).toThrow();
				});
	});
});
